from config.ParseUSBConfig import ParseUSBConfig
from common.eDateTime import eDateTime
from module.usb.USBDetector import USBDetector, USBDevice
from module.usb.USBSCSIDevice import USBSCSIDevice
import os
from datetime import datetime
from subprocess import call

########################################################################
class USBModule():
    """This class is called when USB affector starts the eBackuper program.
       Checks config and do the backup is product/vendor are ok."""
    
    #----------------------------------------------------------------------
    def __init__(self, config, vendor, product):
        """Constructor. Note that config is inside proper section"""
        self.config = config
        self.vendor = vendor
        self.product = product
        
        #0 check - vendor and product
        if not self.config.getUSBVendor() == vendor or not self.config.getUSBProduct() == product:
            self.failBackup("No such vendor or product in config files!")
            return #ends the program

        #1 check - serial
        backupDevice = None
        
        devices = USBDetector().search()
        for device in devices:
            if device.getSerial() == self.config.getUSBSerial():
                backupDevice = USBSCSIDevice(device.getVendor(), device.getProduct(), device.getSerial())
                
        if not backupDevice:
            self.failBackup("No USB device with serial from config no. found!")
            return #ends the program
        
        #2 check - partition count
        #eBackuper uses only one
        
        command = "grep " + backupDevice.getDeviceMap().split('/')[-1] + " /proc/partitions|wc -l"
        partitionCount = int(os.popen(command).readline().rstrip("\n"))
        if partitionCount != 1:
            self.failBackup("USB device doesn't look like formatted by eBackuper! Please use the wizard to prepare device.")
            return
        
        #3 check - ebackuper mark
        if backupDevice.isMounted():
            if not backupDevice.checkDevice():
                self.failBackup("USB device don't have ebackuper mark! Please use the wizard to prepare device.")
                return #ends the program
        else:
            if not os.path.exists("/tmp/ebackuper"):
                os.mkdir("/tmp/ebackuper")
            backupDevice.mount("/tmp/ebackuper")
            
            checkMark = backupDevice.checkDevice()

                        
            if not checkMark:
                self.failBackup("USB device don't have ebackuper mark! Please use the wizard to prepare device.")
                backupDevice.umount()
                os.rmdir("/tmp/ebackuper")
                return #ends the program
                 
        #all checks passed - perform a backup!
        
        makeBackup = False
        doneOk = False
        if config.getUSBMinPeriod():
            files = os.listdir("/tmp/ebackuper/")
            backupFiles = []
            for f in files:
                if f[:10] == "eBackuper_":
                    backupFiles.append(f)
            if len(backupFiles):
                #check time since last backup
                lastBackupDate = sorted(backupFiles)[-1][10:29]
                if eDateTime().isOlderThanXMinutes(lastBackupDate, int(config.getUSBMinPeriod())):
                    makeBackup = True
            else:
                #it's first backup
                makeBackup = True

        if makeBackup:
            backup_command = "tar c " + config.getBackupPath() + " "
            
            if config.getBackupExcludesPath():
                backup_command += "--exclude " + config.getBackupExcludesPath() + " "
            
            if config.isEncrypted():
                backup_command += "| gpg2 --encrypt --keyring " +  config.getEncryptionKey() + " --default-recipient eBackuper " 
            
            backup_command += " > /tmp/ebackuper/eBackuper_" + datetime.now().strftime("%Y-%m-%d-%H:%M:%S") + "_" + config.getOutputFileSuffix()
            if config.isEncrypted():
                backup_command += ".enc"
                
                
            if config.getPreCommand():
                self.callCommand(config.getPreCommand())
            
            print backup_command
	    out = self.callCommand(backup_command)
	    if out:
		# backup has failed - it returns fail message
		reason = out
	    else:
		if config.getPreserveCount() > 1:
		    files = os.listdir("/tmp/ebackuper/")
		    backupFiles = []
		    for f in files:
			if f[:10] == "eBackuper_":
			    backupFiles.append(f)
		    backupFiles = sorted(backupFiles)
		    if len(backupFiles) > config.getPreserveCount():
			toDelete = len(backupFiles) - config.getPreserveCount()
			for i in range (0, toDelete):
			    #delete old backups
			    print "Removing old backup: " + backupFiles[i]
			    os.remove("/tmp/ebackuper/" + backupFiles[i])
		    doneOk = True
		else:
		    print "Error in config file with preserve count! It can't be less than 1! Current value is ",
		    print str(config.getPreserveCount())
		
        else:
            reason = 'Backup not started - not enough time since last backup. It should be at least ' + config.getUSBMinPeriod() + ' minutes.'
        backupDevice.umount()
        os.rmdir("/tmp/ebackuper")
        
        if doneOk:
            if config.getPostCommand():
                self.callCommand(config.getPostCommand())        
        else:
            self.failBackup(reason)

    #----------------------------------------------------------------------
    def failBackup(self, reason):
        print "Backup failed:", reason
        if self.config.getPostFailCommand():
	    print 'call fail command'
            self.callCommand(self.config.getPostFailCommand() % '\"' + reason + '\"')

    #----------------------------------------------------------------------
    def callCommand(self, command):
	out = 0
	try:
		retCode = call(command, shell=True)
		if retCode != 0:
			out = 'Calling ' + command + ' failed with code ' + str(retCode)
	except OSError, e:
		out = 'Calling ' + command + ' failed with: ' + e
	return out
        
    